package org.assistant.common.web.servlet.mvc;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.assistant.common.exception.ParseMethodException;

/**
 * 从URL地址中获取请求的Controller中的函数。<br>
 * 比如：URL地址为/hcm/login/index，则getMethodName()函数得到的函数为：index。
 * 
 * @author zhangQ
 * 
 */
public class InternalPathMethodNameParser implements MethodNameParser {
	protected final static Log log = LogFactory
		.getLog(InternalPathMethodNameParser.class);
	protected final static boolean isDebugEnabled = log.isDebugEnabled();

	private final Map<String, String> methodNameCache = new HashMap<String, String>();

	/**
	 * 获取当前请求的方法名
	 */
	public String getMethodName(HttpServletRequest request)
			throws ParseMethodException {
		return getHandlerMethodName(request);
	}

	/**
	 * 获取当前请求的方法名
	 * 
	 * @param request
	 * @return
	 * @throws ParseMethodException
	 */
	public String getHandlerMethodName(HttpServletRequest request)
			throws ParseMethodException {
		String urlPath = getLookupPathForRequest(request);
		String name = getHandlerMethodNameForUrlPath(urlPath);
		if (name == null) {
			throw new ParseMethodException(urlPath, request.getMethod());
		}
		if (isDebugEnabled) {
			log.debug("Returning handler method name '" + name
					+ "' for lookup path: " + urlPath);
		}
		return name;
	}

	protected String getHandlerMethodNameForUrlPath(String urlPath) {
		String methodName = (String) this.methodNameCache.get(urlPath);
		if (methodName == null) {
			methodName = extractHandlerMethodNameFromUrlPath(urlPath);
			this.methodNameCache.put(urlPath, methodName);
		}
		return methodName;
	}

	protected String extractHandlerMethodNameFromUrlPath(String urlPath) {
		int begin = urlPath.lastIndexOf('/') + 1;
		int end = urlPath.indexOf(';');
		if (end == -1) {
			end = urlPath.indexOf('?');
			if (end == -1) {
				end = urlPath.length();
			}
		}
		String filename = urlPath.substring(begin, end);
		int dotIndex = filename.lastIndexOf('.');
		if (dotIndex != -1) {
			filename = filename.substring(0, dotIndex);
		}
		return filename;
	}

	protected String getLookupPathForRequest(HttpServletRequest request) {
		String rest = getPathWithinServletMapping(request);
		if (!"".equals(rest)) {
			return rest;
		} else {
			return getPathWithinApplication(request);
		}
	}

	protected String getPathWithinServletMapping(HttpServletRequest request) {
		String pathWithinApp = getPathWithinApplication(request);
		String servletPath = request.getServletPath();
		int index = pathWithinApp.indexOf(servletPath);
		if (index > 0) {
			return pathWithinApp.substring(index);
		} else {
			return servletPath;
		}
	}

	protected String getPathWithinApplication(HttpServletRequest request) {
		String contextPath = request.getServletPath();
		String requestUri = request.getRequestURI();
		if (startsWithIgnoreCase(requestUri, contextPath)) {
			String path = requestUri.substring(contextPath.length());
			return (hasText(path) ? path : "/");
		} else {
			return requestUri;
		}
	}

	protected boolean startsWithIgnoreCase(String str, String prefix) {
		if (str == null || prefix == null) {
			return false;
		}
		if (str.startsWith(prefix)) {
			return true;
		}
		if (str.length() < prefix.length()) {
			return false;
		}
		String lcStr = str.substring(0, prefix.length()).toLowerCase();
		String lcPrefix = prefix.toLowerCase();
		return lcStr.equals(lcPrefix);
	}

	protected boolean hasText(CharSequence str) {
		if (str == null || str.length() == 0) {
			return false;
		}
		int strLen = str.length();
		for (int i = 0; i < strLen; i++) {
			if (!Character.isWhitespace(str.charAt(i))) {
				return true;
			}
		}
		return false;
	}
}
